home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / libg_261.zip / libg_261 / libg++ / old-stream / File.cc < prev    next >
C/C++ Source or Header  |  1992-08-12  |  11KB  |  581 lines

  1. /* 
  2. Copyright (C) 1988 Free Software Foundation
  3.     written by Doug Lea (dl@rocky.oswego.edu)
  4.  
  5. This file is part of the GNU C++ Library.  This library is free
  6. software; you can redistribute it and/or modify it under the terms of
  7. the GNU Library General Public License as published by the Free
  8. Software Foundation; either version 2 of the License, or (at your
  9. option) any later version.  This library is distributed in the hope
  10. that it will be useful, but WITHOUT ANY WARRANTY; without even the
  11. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  12. PURPOSE.  See the GNU Library General Public License for more details.
  13. You should have received a copy of the GNU Library General Public
  14. License along with this library; if not, write to the Free Software
  15. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  16. */
  17.  
  18. #ifdef __GNUG__
  19. #pragma implementation
  20. #endif
  21. #include <File.h>
  22. #include <std.h>
  23. #include <stdarg.h>
  24. #include <values.h>
  25. #include <sys/file.h>           // needed to determine values of O_RDONLY...
  26.  
  27.  
  28. #ifdef VMS
  29. #include <errno.h>    // needed to get the psect magic loaded
  30. #define    FP    (*fp)
  31. #else
  32. #define    FP    fp
  33. #endif
  34.  
  35. // error handlers
  36.  
  37. void verbose_File_error_handler(const char* msg)
  38. {
  39.   perror(msg);
  40.   errno = 0;
  41. }
  42.  
  43. void quiet_File_error_handler(const char*)
  44. {
  45.   errno = 0;
  46. }
  47.  
  48. void fatal_File_error_handler(const char* msg)
  49. {
  50.   perror(msg);
  51.   exit(1);
  52. }
  53.  
  54. one_arg_error_handler_t File_error_handler = verbose_File_error_handler;
  55.  
  56.  
  57. one_arg_error_handler_t set_File_error_handler(one_arg_error_handler_t f)
  58. {
  59.   one_arg_error_handler_t old = File_error_handler;
  60.   File_error_handler = f;
  61.   return old;
  62. }
  63.  
  64.  
  65. /*
  66.  
  67.  Opening files. 
  68.  
  69.  open(filename, io_mode, access_mode) is done via system open 
  70.  command since fopen doesn't handle all of the cases possible 
  71.  with sys open. After a successful open, fdopen is called to 
  72.  attach an _iobuf to the file descriptor.
  73.  
  74.  All this requires a few decoding routines that can translate among our
  75.  enumerated types, system flags, and fopen modes.
  76.  
  77. */
  78.  
  79.  
  80. enum sys_open_cmd_io_mode  // These should be correct for most systems
  81. {                        
  82.   sio_read      = O_RDONLY,
  83.   sio_write     = O_WRONLY,
  84.   sio_readwrite = O_RDWR,
  85.   sio_append    = O_APPEND
  86. };
  87.  
  88. enum sys_open_cmd_access_mode
  89. {
  90.   sa_create     = O_CREAT,
  91.   sa_truncate   = O_TRUNC,
  92.   sa_createonly = O_EXCL | O_CREAT
  93. };
  94.  
  95.   
  96. static int open_cmd_arg(io_mode i, access_mode a) // decode modes
  97. {
  98.   int arg;
  99.   switch(i)
  100.   {
  101.   case io_readonly:   arg = sio_read;                   break;
  102.   case io_writeonly:  arg = sio_write;                  break;
  103.   case io_readwrite:  arg = sio_readwrite;              break;
  104.   case io_appendonly: arg = sio_append | sio_write;     break;
  105.   case io_append:     arg = sio_append | sio_readwrite; break;
  106.   default:            return -1;
  107.   };
  108.   switch(a)
  109.   {
  110.   case a_createonly:  return arg | sa_createonly;
  111.   case a_create:      return arg | sa_create | sa_truncate;
  112.   case a_useonly:     return arg;
  113.   case a_use:         return arg | sa_create;
  114.   default:            return -1;
  115.   }
  116. }
  117.  
  118. static char* fopen_cmd_arg(io_mode i)
  119. {
  120.   switch(i)
  121.   {
  122.   case io_readonly:  return "r";
  123.   case io_writeonly: return "w";
  124.   case io_readwrite: return "r+";
  125.   case io_appendonly:return "a";
  126.   case io_append:    return "a+";
  127.   default:           return 0;
  128.   }
  129. }
  130.  
  131.  
  132. void File::initialize() 
  133.   fp = 0; nm = 0; stat = 0; state = _bad; rw = 0;
  134. }
  135.  
  136. // reset class vars after open
  137. // fp->_flag inspection is isolated here
  138.  
  139. void File::reinitialize(const char* filename)
  140. {
  141.   if (filename != 0)     setname(filename);
  142.   else if (fp == stdin)  setname("(stdin)");
  143.   else if (fp == stdout) setname("(stdout)");
  144.   else if (fp == stderr) setname("(stderr)");
  145.   else if (rw & 4)       setname("(string)");
  146.   else setname(0);
  147.  
  148.   if (fp != 0)
  149.   {
  150.     state = _good;
  151.     if (FP->_flag & (_IOREAD|_IORW))
  152.       rw |= 01;
  153.     if (FP->_flag & (_IOWRT|_IORW))
  154.       rw |= 02;
  155.     check_state();
  156.   }
  157.   else
  158.   {
  159.     set(_fail); set(_bad);
  160.     error();
  161.   }
  162. }
  163.  
  164.  
  165. File& File::open(const char* filename, io_mode m, access_mode a)
  166. {                                   
  167.   close();
  168.   int open_arg = open_cmd_arg(m, a);
  169.   if (open_arg != -1)
  170.   {
  171.     int fd = ::open(filename, open_arg, 0666);
  172.     if (fd >= 0)
  173.       fp = fdopen(fd, fopen_cmd_arg(m));
  174.   }
  175.   reinitialize(filename);
  176.   return *this;
  177. }
  178.  
  179. File& File::open(const char* filename, const char* m)
  180. {                                   
  181.   close();
  182.   fp = fopen(filename, m);
  183.   reinitialize(filename);
  184.   return *this;
  185. }
  186.  
  187. File& File::open(FILE* fileptr)
  188. {
  189.   close();
  190.   fp = fileptr;
  191.   reinitialize(0);
  192.   return *this;
  193. }
  194.  
  195. File& File::open(int filedesc, io_mode m)
  196. {
  197.   close();
  198.   fp = fdopen(filedesc, fopen_cmd_arg(m));
  199.   reinitialize(0);
  200.   return *this;
  201. }
  202.  
  203. File& File::close()
  204. {
  205.   if (fp != 0)
  206.   {
  207. #ifdef VMS
  208.     if (rw & 4)                 // we own the iobuf, kill it
  209.       delete(*fp);    // kill the _iobuf
  210. #endif
  211.     if (rw & 4)                 // we own the iobuf, kill it
  212.       delete fp;
  213.     else if (fp == stdin || fp == stdout || fp == stderr)
  214.       flush();
  215.     else
  216.       fclose(fp);
  217.   }
  218.   fp = 0;
  219.   rw = 0;
  220.   set(_bad);
  221.   return *this;
  222. }
  223.  
  224. File& File::remove()
  225. {
  226.   close();
  227.   return failif (nm == 0 || unlink(nm) != 0);
  228. }
  229.  
  230.  
  231. File::File()
  232.   initialize(); 
  233. }
  234.  
  235. File::File(const char* filename, io_mode m, access_mode a)   
  236.   initialize(); 
  237.   open(filename, m, a); 
  238. }
  239.  
  240. File::File(const char* filename, const char* m)   
  241.   initialize(); 
  242.   open(filename, m); 
  243. }
  244.  
  245. File::File(int filedesc, io_mode m)
  246.   initialize(); 
  247.   open(filedesc, m); 
  248. }
  249.  
  250. File::File(FILE* fileptr)
  251.   initialize(); 
  252.   open(fileptr); 
  253. }
  254.  
  255. File::File(int sz, char* buf, io_mode m)
  256. {
  257.   if (m != io_readonly && m != io_writeonly)
  258.     (*File_error_handler) ("invalid io_mode for string IO");
  259.   initialize();
  260.   rw = 4;
  261. #ifdef VMS
  262.   _iobuf    *iob;
  263.   FILE        *f;
  264.  
  265.   iob = new _iobuf;
  266.   f = new(FILE);
  267.   *f = iob;
  268.   fp = f;
  269. #else
  270.   fp = new _iobuf;
  271. #endif
  272. #ifndef _NFILE
  273.   FP->_file = 255;          // any illegal value
  274. #else
  275.   FP->_file = _NFILE-1;       // The last filedescriptor...
  276. #ifdef BUFEND_ENTRY_TYPE
  277.   _bufendtab[FP->_file] = (BUFEND_ENTRY_TYPE)buf+sz-1;
  278. #endif
  279. #endif
  280.   FP->_ptr = FP->_base = buf;
  281. #ifdef HAVE_BUFSIZ
  282.   FP->_bufsiz = sz;
  283. #endif
  284.   if (m == io_readonly)
  285.   {
  286.     int len = 0;
  287.     while (len < sz && buf[len] != 0) ++len;
  288.     if (len == sz)
  289.       buf[sz - 1] = 0;            // force null-termination!
  290.     FP->_cnt = len;
  291.     FP->_flag = _IOREAD | _IOSTRG | _IOMYBUF;
  292.   }
  293.   else
  294.   {
  295.     bzero(buf, sz);             // so any result will be null-terminated
  296.     FP->_cnt = sz - 1;          // leave at least one null at end
  297.     FP->_flag = _IOWRT | _IOSTRG | _IOMYBUF;
  298.   }
  299.   reinitialize(0);
  300. }
  301.  
  302. File::~File()
  303. {
  304.   delete(nm);
  305.   close();
  306. }
  307.  
  308. void File::setname(const char* newname)
  309. {
  310.   if (nm == newname) return;
  311.  
  312.   if (nm != 0)
  313.     delete(nm);
  314.   if (newname != 0)
  315.   {
  316.     nm = new char[strlen(newname) + 1];
  317.     strcpy(nm, newname);
  318.   }
  319.   else
  320.     nm = 0;
  321. }
  322.  
  323.  
  324. File& File::setbuf(int buffer_kind)
  325. {                  
  326.   if (!is_open())
  327.   {
  328.     set(_fail);
  329.     return *this;
  330.   }
  331.   switch(buffer_kind)
  332.   {
  333.   case _IOFBF:       
  334. #ifdef HAVE_SETVBUF
  335.     setvbuf(fp, 0, _IOFBF, 0);
  336. #endif
  337.     break;           
  338.   case _IONBF:       
  339.     ::setbuf(fp, 0); 
  340.     break;
  341.   case _IOLBF:
  342. #ifdef HAVE_SETLINEBUF
  343.     setlinebuf(fp);
  344. #else
  345. #ifdef HAVE_SETVBUF
  346.     setvbuf(fp, 0, _IOLBF, 0);
  347. #endif
  348. #endif    
  349.     break;
  350.   default:
  351.     break;
  352.   }
  353.   return *this;
  354. }
  355.  
  356. File& File::setbuf(int size, char* buf)
  357. {
  358.   if (!is_open())
  359.   {
  360.     set(_fail);
  361.     return *this;
  362.   }
  363. #ifdef HAVE_SETVBUF
  364.   setvbuf(fp, buf, _IOFBF, size);
  365. #else
  366.   setbuffer(fp, buf, size);
  367. #endif
  368.   return *this;
  369. }
  370.  
  371. void File::error()
  372. {
  373.   check_state();
  374.   set(_fail);
  375.   if (errno != 0)
  376.   {
  377.     char error_string[400];
  378.     strcpy(error_string, "\nerror in File ");
  379.     if (nm != 0)
  380.       strcat(error_string, nm);
  381.     (*File_error_handler)(error_string);
  382.   }
  383. }
  384.  
  385.  
  386. //------------------------------------------------------------------
  387.  
  388. void File::check_state() // ensure fp & state agree about eof
  389. {
  390.   if (fp != 0)
  391.   {
  392.     if (feof(fp))
  393.       set(_eof);
  394.     else
  395.       unset(_eof);
  396.     if (ferror(fp))
  397.       set(_bad);
  398.   }
  399. }
  400.  
  401. File& File::put(const char* s)
  402.   return failif(!writable() || fputs(s, fp) == EOF);
  403. }
  404.  
  405. File& File::get(char* s, int n, char terminator)
  406. {
  407.   if (!readable())
  408.   {
  409.     set(_fail);
  410.     return *this;
  411.   }
  412.  
  413.   char ch;
  414.   stat = --n;
  415.  
  416.   if (n > 0 && (get(ch)))
  417.   {
  418.     if (ch == terminator) {
  419.       unget(ch);
  420.       stat= 0;    // This is not an error condition !
  421.     }
  422.     else
  423.     {
  424.       *s++ = ch; --n;
  425.       while (n > 0 && (get(ch)))
  426.       {
  427.         if (ch == terminator)
  428.         {
  429.           unget(ch);
  430.           break;
  431.         }
  432.         else
  433.         {
  434.           *s++ = ch; --n;
  435.         }
  436.       }
  437.     }
  438.   }
  439.  
  440.   *s = 0;
  441.   return failif((stat != 0) && ((stat -= n) == 0));
  442. }
  443.  
  444. File& File::getline(char* s, int n, char terminator)
  445. {
  446.   if (!readable())
  447.   {
  448.     set(_fail);
  449.     return *this;
  450.   }
  451.  
  452.   char ch;
  453.   stat = --n;
  454.  
  455.   while (n > 0 && (get(ch)))
  456.   {
  457.     --n;
  458.     if ((*s++ = ch) == terminator)
  459.       break;
  460.   }
  461.  
  462.   *s = 0;
  463.   return failif((stat != 0) && ((stat -= n) == 0));
  464. }
  465.  
  466. // from Doug Schmidt
  467.  
  468. // This should probably be a page size....
  469. #define CHUNK_SIZE 512
  470.  
  471. /* Reads an arbitrarily long input line terminated by a user-specified
  472.    TERMINATOR.  Super-nifty trick using recursion avoids unnecessary calls
  473.    to NEW! */
  474.  
  475. char *File::readline (int chunk_number, char terminator) 
  476. {
  477.   char buf[CHUNK_SIZE];
  478.   register char *bufptr = buf;
  479.   register char *ptr;
  480.   char ch;
  481.   int continu;
  482.  
  483.   while ((continu = !!get(ch)) && ch != terminator) /* fill the current buffer */
  484.     {
  485.       *bufptr++ = ch;
  486.       if (bufptr - buf >= CHUNK_SIZE) /* prepend remainder to ptr buffer */
  487.         {
  488.           if (ptr = readline (chunk_number + 1, terminator))
  489.  
  490.             for (; bufptr != buf; *--ptr = *--bufptr);
  491.  
  492.           return ptr;
  493.         }
  494.     }
  495.   if (!continu && bufptr == buf)
  496.     return NULL;
  497.  
  498.   int size = (chunk_number * CHUNK_SIZE + bufptr - buf) + 1;
  499.  
  500.   if (ptr = new char[stat = size])
  501.     {
  502.  
  503.       for (*(ptr += (size - 1)) = '\0'; bufptr != buf; *--ptr = *--bufptr)
  504.         ;
  505.  
  506.       return ptr;
  507.     } 
  508.   else 
  509.     return NULL;
  510. }
  511.  
  512. /* Reads an arbitrarily long input line terminated by TERMINATOR.
  513.    This routine allocates its own memory, so the user should
  514.    only supply the address of a (char *). */
  515.  
  516. File& File::gets(char **s, char terminator)
  517. {
  518.   if (!readable())
  519.   {
  520.     set(_fail);
  521.     return *this;
  522.   }
  523.  
  524.   return failif(!(*s = readline (0, terminator)));
  525. }
  526.   
  527. #ifndef VMS
  528. File& File::scan(const char* fmt ...)
  529. {
  530.   if (readable())
  531.   {
  532.     va_list args;
  533.     va_start(args, fmt);
  534. #ifndef HAVE_VSCANF
  535.     stat = _doscan(fp, fmt, args);
  536. #else
  537.     stat = vfscanf(fp, fmt, args);
  538. #endif
  539.     va_end(args);
  540.     failif(stat <= 0);
  541.   }
  542.   return *this;
  543. }
  544. #endif
  545.  
  546. File& File::form(const char* fmt ...)
  547. {
  548.   va_list args;
  549.   va_start(args, fmt);
  550. #ifndef HAVE_VPRINTF
  551.   stat = _doprnt(fmt, args, fp);
  552. #ifdef HAVE_VOID_DOPRNT
  553.   stat = ferror(fp) ? -1 : 0;
  554. #endif
  555. #else
  556.   stat = vfprintf(fp, fmt, args);
  557. #endif
  558.   va_end(args);
  559.   failif(stat < 0);
  560.   return *this;
  561. }
  562.  
  563. #ifdef VMS
  564. extern "C" {
  565.     unlink(const char *s)
  566.     {
  567.         int remove(const char *);
  568.  
  569.         return remove(s);
  570.     }
  571. }
  572. #endif
  573.  
  574.